﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Db4objects.Db4o.Config;
using Db4objects.Db4o;
using System.Windows;
using System.IO;
using DocManagerORM.ORM;
using Db4objects.Db4o.Cluster;
using Db4objects.Db4o.Defragment;
using Db4objects.Db4o.Ext;
using Db4objects.Db4o.Constraints;
using Db4objects.Db4o.CS;

namespace DocManagerORM.DB4O
{
   public class DB4OBase
    {
     
       public IObjectContainer Database { get; set; }

       public static string getPathDBFilefromConfig(string pDB4ODirectoryPath)
       {
           return  System.Configuration.ConfigurationManager.AppSettings[pDB4ODirectoryPath];
           
       }//fM

       public string DBName { get; set; }
       public string DatabaseDirectory { get; set; }

      
       public DB4OBase()
       {
           OpenDB(null);
       }//fM

       public DB4OBase(string pDBName,string pPathDirectory  )
       {
           DBName = pDBName;
           DatabaseDirectory = pPathDirectory;
           OpenDB(pDBName);           
       }//fM


       private void openClient(string pFilePathDB,int pPorta,string pUserName,string pPwd)
       {
         var db=  Db4oClientServer.OpenClient(Db4oClientServer.NewClientConfiguration(),
                pFilePathDB, pPorta, pUserName, pPwd);   
   
       }//fM

       private void openServer(string pFilePathDB, int pPorta)
       {
           var db = Db4oClientServer.OpenServer(Db4oClientServer.NewServerConfiguration(), pFilePathDB, pPorta);

       }//fM


       private void OpenDB(string pDBName)
       {
           if (Database != null) return;

         
           if(string.IsNullOrEmpty(DatabaseDirectory))
           {
               messaggia("Impossibile aprire il database db4 : Nome directory mancante nel file di configurazione "); return;
           }

           if (string.IsNullOrEmpty(pDBName.Trim()))
           {
               var dbFileName = getPathDBFilefromConfig("DB4ODbFileName");
               if (string.IsNullOrEmpty(dbFileName))
               {
                   messaggia("Impossibile aprire il database db4 : Nome file Db mancante nel file di configurazione "); return;
               }
               DBName = dbFileName;
           }
           else
               DBName = pDBName;

           if (!Directory.Exists(DatabaseDirectory)) Directory.CreateDirectory(DatabaseDirectory);
           var pathDB = Path.Combine(DatabaseDirectory, DBName);
           if (!File.Exists(pathDB)) File.Create(pathDB);

           var blobPath = Path.Combine(DatabaseDirectory, "DocsDb4Directory");//<< TODO : spostare su filke configurazione
           if (!Directory.Exists(blobPath)) Directory.CreateDirectory(blobPath);
           
           //IEmbeddedConfiguration configuration = Db4oEmbedded.NewConfiguration();//per embedded database
           //var cliSer = configuration.ClientServer();                
           var configuration = Db4objects.Db4o.Db4oFactory.Configure();
           
           configuration.AllowVersionUpdates(true);
           configuration.ActivationDepth(3);
           configuration.UpdateDepth(3);
           configuration.TestConstructors(false);
           configuration.GenerateVersionNumbers(ConfigScope.Globally);//< ID Globali per tutto il db
           configuration.SetBlobPath(blobPath);

           InitializeIndexes(ref configuration);

           Database = Db4oFactory.OpenFile(configuration, pathDB);           
           //Db4oFactory.OpenClient(configuration);  
       }

       public void BackupDB(string pPathBackup )
       {
           Database.Ext().Backup(pPathBackup);
        //IObjectServer.Ext().Backup(string path)
       
       }//fM

       public IStoredClass[] GetMetaObjects()
       {
           try
           {
               //Db4objects.Db4o.Ext.IStoredClass sc = container.Ext().StoredClass(typeof(Car));
               IStoredClass[] sclasses = Database.Ext().StoredClasses();
               return sclasses;
           }
           catch { return null; }
       }

       public IStoredClass GetMetaObjects<T>()
       {
           try
           {
               IStoredClass sc = Database.Ext().StoredClass(typeof(T));
               return sc;
           }
           catch { return null; }
       }
       
       private void InitializeIndexes(ref IConfiguration pIConfigurazione)
       {
           //pIConfigurazione.ObjectClass(typeof(Categorie)).GenerateVersionNumbers(true); 
           pIConfigurazione.ObjectClass(typeof(Categorie)).ObjectField("Categoria").Indexed(true);
           pIConfigurazione.Add(new UniqueFieldValueConstraint(typeof(Categorie), "Categoria"));//< vincolo univocità
             
       }
       
       private void IndicizzaInteroOggetto<T>(ref IConfiguration pIConfigurazione)
       {
           pIConfigurazione.ObjectClass(typeof(T)).Indexed(true);
       }

       private void IndicizzaCampiOggetto<T>(ref IConfiguration pIConfigurazione, params string[] pNomeCampi )
       {
           pIConfigurazione.ObjectClass(typeof(T)).Indexed(true);
       }
       
       public void Backupdatabase(string pPathDirectory,string pPathFileDbName)
       {
           try
           {
               if (!Directory.Exists(pPathDirectory))
               {
                   Directory.CreateDirectory(pPathDirectory);
               }

               var path = Path.Combine(pPathDirectory, pPathFileDbName);

               Database.Ext().Backup(path);
           }
           catch (Exception ex)
           {
               messaggia("Impossibile eseguire il backup del Db4 : \r\n"+ ex.Message); 
           }
       }//fM
       
       public  bool tryOpenConn(bool pMessaggia, bool pCloseImmediately)
       {           
           try
           {
                OpenDB(DBName);
               if (pCloseImmediately)Database.Close();
  
               return true;
           }
           catch (Exception ex)
           {
               MessageBox.Show("Attenzione : Errore apertura database Db4 : \r\n" + ex.Message);
               return false;
           }

       }//fM
              
       public void UpdateObject<T>(T pObject)
       {
           try
           {
               // open the db4o-session. For example at the beginning for a web-request
               using (var session = Database.Ext().OpenSession())
               {
                   try
                   {
                      session.Store(pObject);
                      session.Commit();
                   }
                   catch (Exception ex)
                   {
                       session.Rollback();
                   }

               }

               Database.Commit();
           }
           catch (Exception ex)
           {
               Database.Rollback();
               throw;
           }
       
       }//fM
       
       public void UpdateObjects<T>(IEnumerable<T> pListObject)
       {
           try
           {               
                   // open the db4o-session. For example at the beginning for a web-request
               using (var session = Database.Ext().OpenSession())
                   {
                       try
                       {
                           foreach (var item in pListObject)
                           {
                               session.Store(item);
                           }
                           session.Commit();  
                       }
                       catch (Exception ex)
                       {
                           session.Rollback();  
                       }
                            
                   }               

               Database.Commit(); 
           }
           catch (Exception ex)
           {
               Database.Rollback(); 
               throw;
           }
       
       }//fM

       public void DeleteObject(Object pObject)
       {
           try
           {
               // open the db4o-session. For example at the beginning for a web-request
               Database.Delete(pObject); 
               Database.Commit();
           }
           catch (Exception ex)
           {
               Database.Rollback();
               throw;
           }

       }//fM

       public void InsertObject(Object pObject)
       {
           try
           {
               Database.Store(pObject);
               Database.Commit();
              
           }
           catch (Exception ex)
           {
               Database.Rollback();
               throw;
           }

       }//fM
       
       public IList<T> queryOggetti<T>(Predicate<T> pWhere)
       {
           if (pWhere == null)
               return Database.Query<T>();               
           else
               return Database.Query<T>(pWhere);               
           
           //Database.Ext().Refresh(pilot, int.MaxValue);
       }//fM

       public IObjectSet QueryByExemples<T>( T pObject)
       {
          var res = Database.QueryByExample(pObject);
          return res;
       
       }//fM


       protected void messaggia(string pMessage)
       {
           MessageBox.Show(pMessage, "Avvisi", MessageBoxButton.OK, MessageBoxImage.Information);
       }//fM


       public void DeframmentaDatabase()
       {           
           DefragmentConfig config = new DefragmentConfig(DBName);
           config.ForceBackupDelete(true);
           Defragment.Defrag(config);
             
       }//fM

       public IObjectSet queryClusterOfDB<T>(Cluster pClusterDiDb)
       { 
        //Now use Soda queries for retrieving objects. 
        IObjectContainer obj1 = Db4oFactory .OpenFile("yourfile1.yap"); 
        IObjectContainer obj2 = Db4oFactory.OpenFile("yourfile2.yap"); 
           //settare configurazione se desiderato
        IObjectContainer[] ocArr= {obj1,obj2}; 
        Cluster c = new Cluster(ocArr); 
        var q = c.Query(); 
        q.Constrain(typeof(T)); 
        IObjectSet res= q.Execute();
        return res;
       
       }//fM

       public IEnumerable<T> queryClusterOfDB<T>(Cluster pClusterDiDb,bool pNull)
       {
           //Now use Soda queries for retrieving objects. 
           IObjectContainer obj1 = Db4oFactory.OpenFile("yourfile1.yap");
           IObjectContainer obj2 = Db4oFactory.OpenFile("yourfile2.yap");
           //settare configurazione se desiderato
           IObjectContainer[] ocArr = { obj1, obj2 };
           Cluster c = new Cluster(ocArr);
           var q = c.Query();
           q.Constrain(typeof(T));
           var res = q.Execute().Cast<T>();
           return res;

       }//fM


   
   }//fC





}
